-- $Id: $
-- File name:   RCU.vhd
-- Created:     10/6/2010
-- Author:      Christopher Sakalis
-- Lab Section: 4
-- Version:     1.0  Initial Design Entry
-- Description: RCU (Receiver Control Unit).


LIBRARY IEEE;
USE IEEE.std_logic_1164.ALL;
USE IEEE.std_logic_unsigned.ALL;

entity RCU is
  Port ( CLK : in std_logic;
       RST_N : in std_logic;
      D_EDGE : in std_logic;
         EOP : in std_logic;
SHIFT_ENABLE : in std_logic;
    RCV_DATA : in std_logic_vector (7 downto 0);
     CHK_OUT : out std_logic;
      RCVING : out std_logic;
    W_ENABLE : out std_logic;
     R_ERROR : out std_logic
        );
end RCU;



architecture Behavioral of RCU is

  type state_type is (IDLE, EIDLE,rcu1_RCV_1, rcu1_RCV_2, rcu2_CMP, rcu3_R_IDLE, rcu4_R_IDLE, rcu0_STORE, rcu0_STORE2, WAIT_DE, WAIT_DE2, EIDLE_R, WAIT_DE_R, WAIT_DE2_R);
  signal state,nextstate : state_type;
  signal myCount, nextCount: std_logic_vector(3 downto 0);
  signal stCount, stNextCount: std_logic_vector(3 downto 0);
  signal thiCount, thiNextCount: std_logic_vector(3 downto 0);
  signal rCount, rNextCount: std_logic_vector(3 downto 0);

  signal fCount, fNextCount: std_logic_vector(3 downto 0); --the counter used to count up to 6...

  signal STRT : std_logic;
  signal STRT_st : std_logic;
  signal STRT_thi : std_logic;
  signal STRT_r : std_logic;


  signal STRT_f : std_logic; --Signal used to begin counting up to 6 to keep track of the six bits shifted in.
  signal STRT_4 : std_logic; --Signal used to set the Bit-Stuffing counter to one when searching for the SYNC Byte.
  --signal CHK : std_logic;

  --signal CLR : std_logic;
  --signal RCV_temp: std_logic_vector(7 downto 0);

begin
 RCU_Reg: process (CLK, RST_N)
 begin
   if (RST_N='0') then
     state <= IDLE;
   elsif (CLK'event and CLK='1') then
     state <= nextstate;
   end if;
 end process RCU_Reg;


--=================================================
---------------------------------------------------
--General Counter (used in RCV_1 and RCV_2 to keep track of clk cycles past.)
 StateReg : process (CLK, RST_N)
 begin
   if (RST_N = '0') then
     myCount <= (others => '0');
   elsif (CLK'event and CLK = '1') then
     myCount <= nextCount;
   end if;
 end process;

--This should be the next state logic
   process(myCount,SHIFT_ENABLE,EOP,STRT)
   begin
     if (CONV_INTEGER(myCount) = 8) or (EOP='1') or (STRT='0') then
       nextCount <= "0000";
     --elsif (SHIFT_ENABLE = '1') then --start counting
     elsif ((SHIFT_ENABLE = '1') and (CONV_INTEGER(myCount) < 8) and (STRT='1')) then --start counting
       nextCount <= myCount + 1;
     else
       nextCount <= myCount;
     end if;
   end process;
-----------------------------------------------------
--$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
--Second counter Logic (Store2 -> RCV2) [DATA received -> KEEP receiving new DATA ]
 SecReg : process (CLK, RST_N)
 begin
   if (RST_N = '0') then
     stCount <= (others => '0');
   elsif (CLK'event and CLK = '1') then
     stCount <= stNextCount;
   end if;
 end process;

--This should be the next state logic for the second counter
   process(stCount,EOP,STRT_st)
   begin
     if (CONV_INTEGER(stCount) = 4) or (EOP='1') or (STRT_st='0') then
       stNextCount <= "0000";
     elsif ((CONV_INTEGER(stCount) < 4) and (STRT_st='1')) then --start counting
       stNextCount <= stCount + 1;
     else
       stNextCount <= stCount;
     end if;
   end process;
--$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
--====================================================


--====================================================
--&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
--Third counter Logic (Store2 -> WAIT_DE) [Data received -> STOP receiving new DATA]
 ThiReg : process (CLK, RST_N)
 begin
   if (RST_N = '0') then
     thiCount <= (others => '0');
   elsif (CLK'event and CLK = '1') then
     thiCount <= thiNextCount;
   end if;
 end process;

--This should be the next state logic for the THIRD counter
   process(thiCount,STRT_thi)
   begin
     if (CONV_INTEGER(thiCount) = 3) or (STRT_thi='0') then
       thiNextCount <= "0000";
     elsif ((CONV_INTEGER(thiCount) < 3) and (STRT_thi='1')) then --start counting
       thiNextCount <= thiCount + 1;
     else
       thiNextCount <= thiCount;
     end if;
   end process;
--&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
--====================================================


--====================================================
--****************************************************
--ERROR counter Logic
 rReg : process (CLK, RST_N)
 begin
   if (RST_N = '0') then
     rCount <= (others => '0');
   elsif (CLK'event and CLK = '1') then
     rCount <= rNextCount;
   end if;
 end process;

--This should be the next state logic for the ERROR counter
   process(rCount,STRT_r)
   begin
     if (CONV_INTEGER(rCount) = 3) or (STRT_r='0') then
       rNextCount <= "0000";
     elsif ((CONV_INTEGER(rCount) < 3) and (STRT_r='1')) then --start counting
       rNextCount <= rCount + 1;
     else
       rNextCount <= rCount;
     end if;
   end process;
--****************************************************
--====================================================


--====================================================
--444444444444444444444444444444444444444444444444444444444444444444444
--FOURTH!!!! counter Logic
 fReg : process (CLK, RST_N)
 begin
   if (RST_N = '0') then
     fCount <= (others => '0');
   elsif (CLK'event and CLK = '1') then
     fCount <= fNextCount;
   end if;
 end process;

--The Fourth counter is operating similarly to the myCount.
--Also it counts 0-1-2-3-4-5 => counted 6

--This should be the next state logic for the FOURTH counter
   process(fCount,STRT_f,STRT_4,D_EDGE,SHIFT_ENABLE)
   begin
     if (D_EDGE='1')  then
       fNextCount <= "0000";
     elsif (STRT_4='1') then
       fNextCount <= "0010";
     elsif ((CONV_INTEGER(fCount) < 8) and (STRT_f='1') and (SHIFT_ENABLE='1')) then --start counting
       fNextCount <= fCount + 1;
     elsif (CONV_INTEGER(fCount) = 8) then
       fNextCount <= "0010";
     else
       fNextCount <= fCount;
     end if;
   end process;
--444444444444444444444444444444444444444444444444444444444444444444444
--====================================================





  --Next_state: process (state, D_EDGE, SHIFT_ENABLE, EOP, myCount, stCount, RCV_temp)
  Next_state: process (state, D_EDGE, SHIFT_ENABLE, EOP, myCount, stCount, thiCount, rCount, RCV_DATA, fCount)
  begin
   --Default Cases.
    RCVING <= '1';
    W_ENABLE <= '0';
    R_ERROR <= '0';
    STRT <= '0';
    STRT_st <='0';
    STRT_thi<='0';
    STRT_r<='0';
    CHK_OUT<='0';
    STRT_f<='0';
    STRT_4<='0';
    nextstate<=state;
--=================================================
    case state is
--=================================================
      when IDLE => --IDLE/RST state.
         RCVING <= '0';
         W_ENABLE <= '0';
         R_ERROR <= '0';
         STRT <= '0';
         if (D_EDGE = '1') then nextstate <= rcu1_RCV_1;
         else                   nextstate <= IDLE;
         end if;
--=================================================
      when rcu1_RCV_1 =>
         R_ERROR <= '0';
         RCVING <='1'; --Begin receiving data by assarting RCVING.
         W_ENABLE<='0';
         --Begin counting
         STRT <= '1';
         --Set Bit-Stuffing counter to 1
         STRT_4 <= '1';
         --Next state logic from the RCV state.
         if (EOP = '1') then
           nextstate <= rcu3_R_IDLE;
         elsif (CONV_INTEGER(myCount) = 8) then
           nextstate <= rcu2_CMP;
          else
            nextstate <= rcu1_RCV_1;
         end if;

--=================================================
      when rcu2_CMP =>
         STRT <= '0';
         --if (RCV_temp = "10000000") then --10000000 is the SYNC byte.
         if (RCV_DATA = "10000000") then --10000000 is the SYNC byte.
           --do not store the byte into the FIFO, but begin recieving and storing data from the next byte
           nextstate <= rcu1_RCV_2;
         else
           nextstate <= rcu4_R_IDLE;
         end if;
--=================================================
      when rcu1_RCV_2 =>
         RCVING <='1'; --Begin receiving data by assarting RCVING.
         W_ENABLE<='0';
         --Begin counting
         STRT <= '1';

         --Begin counting for six identical bits.
         STRT_f <='1';

         --Next state logic from the RCV state.
         if (EOP = '1') then
           nextstate <= rcu3_R_IDLE;
         elsif (CONV_INTEGER(myCount) = 8) then
           nextstate <= rcu0_STORE;
          else
            nextstate <= rcu1_RCV_2;
         end if;

         if (CONV_INTEGER(fCount) = 8) then
           CHK_OUT <='1';
         end if;

----NEED TO TEST THIS ONE:
-- --           if ( (RCV_DATA(7 downto 2) = "000000") or (RCV_DATA(7 downto 2) = "111111") ) then
-- --             CHK_OUT <='1';
-- --             --RCV_DATA <= (not RCV_DATA(7)) & RCV_DATA(7 downto 1);
-- --           end if;

--=================================================
      when rcu3_R_IDLE =>
         --set the R_ERROR flag to a 1
         --and disregard any input until the next EOP is reached.
         --The RCVING line should remain high until the EOP is reached.
         --Keep the R_ERROR flag high until the next packet begins.
         R_ERROR<='1';
         W_ENABLE<='0';
         RCVING <= '0';
         STRT <= '0';
          if (D_EDGE='1') then
          --if (EOP='0') then
            nextstate <= EIDLE_R;
          end if;

--=================================================
      when rcu4_R_IDLE =>
         --set the R_ERROR flag to a 1
         --and disregard any input until the next EOP is reached.
         --The RCVING line should remain high until the EOP is reached.
         --Keep the R_ERROR flag high until the next packet begins.
         R_ERROR<='1';
         W_ENABLE<='0';
         STRT <= '0';
--          if (D_EDGE='1') then
--            nextstate <= rcu1_RCV_1;
--          end if;
         if (EOP = '1') then
           nextstate <= WAIT_DE2_R;
         end if;
--=================================================
--       when rcu0_STORE =>
--          -- o If an EOP is reached with an incomplete byte in the shift register (i.e. the
--          -- EOP should occur just after a byte is shifed into the FIFO), set the
--          -- ERROR flag high and do not store the last byte. Leave the R_ERROR
--          -- flag high until the next packet begins.

      when rcu0_STORE =>
         W_ENABLE<='1';
         STRT <= '0';
         nextstate <= rcu0_STORE2;

      when rcu0_STORE2 =>
         STRT_st <= '1';
         if (EOP = '1') then
           nextstate <= WAIT_DE2;
         elsif (CONV_INTEGER(stCount) = 3) then
           nextstate <= rcu1_RCV_2;
         else
            nextstate <= rcu0_STORE2;
         end if;

--=================================================
--=================================================
--WAIT_DE2 -> WAIT_DE -> EIDLE
--These state transitions occur ONLY WHEN THE DATA HAS BEEN SUCCESSFULLY RECEIVED.
      when  WAIT_DE=>
         RCVING <= '0';
          if (D_EDGE = '1') then
          --if (EOP = '0') then
            nextstate <= EIDLE;
         end if;
----------------------------------------------------
      when  WAIT_DE2=>
      --we wait for 2 clk cycles so to avoid the first D_EDGE.
         RCVING <= '0';
         STRT_thi <= '1';
         if (CONV_INTEGER(thiCount) = 1) then
            nextstate <= WAIT_DE;
         end if;
----------------------------------------------------
      when  EIDLE=>
      --we wait for the next D_EDGE in order to go back to the rcving state
         RCVING <= '0';
         if (D_EDGE = '1') then
           nextstate <= rcu1_RCV_1;
         end if;

--------------------------------------------------
--************************************************
--************************************************

--WAIT_DE2_R -> WAIT_DE_R -> EIDLE_R
--This state transitions occurs ONLY WHEN AN ERROR HAS OCCURED  
      when  WAIT_DE_R=>
         RCVING <= '0';
         R_ERROR<='1';
          if (D_EDGE = '1') then
          --if (EOP = '0') then
            nextstate <= EIDLE_R;
         end if;

----------------------------------------------------

      when  WAIT_DE2_R=>
      --we wait for 2 clk cycles so to avoid the first D_EDGE.
         RCVING <= '0';
         R_ERROR<='1';
         STRT_r <= '1';
         if (CONV_INTEGER(rCount) = 1) then
            nextstate <= WAIT_DE_R;
         end if;
----------------------------------------------------
      when  EIDLE_R=>
      --we wait for the next D_EDGE in order to go back to the rcving state.
         R_ERROR<='1';
         RCVING <= '0';
         if (D_EDGE = '1') then
           nextstate <= rcu1_RCV_1;
         end if;

--************************************************
--************************************************
--------------------------------------------------
--=================================================
--=================================================

       when others => nextstate <= IDLE;
    end case;
 end process Next_state;

end Behavioral;